/*
	Copyright Christopher Diggins 2008
	Licensed under LGPL version 3.0
	http://cppscript.googlecode.com
*/

#ifndef YARD_CPPSCRIPT_GRAMMAR_HPP
#define YARD_CPPSCRIPT_GRAMMAR_HPP

#include "yard_shared_grammar.hpp"

namespace cppscript_grammar
{
	using namespace shared_grammar;

	struct Expr;
    struct TypeExpr;
    struct SimpleExpr;
    struct Statement;
    struct StatementList;
    struct CodeBlock;

	struct NameTok :
		Seq<Store<Name>, WS> { };

    struct Arg :
        Seq<VAR, NameTok > { };

    struct ArgList :        
        StoreCommaList<CharTok<'('>, Arg, CharTok<')'> > { };

    struct ParanthesizedExpr :
        NoFailSeq<CharTok<'('>, Star<Seq<Store<Expr>, Opt<CharTok<','> > > >, CharTok<')'> > { };

    struct BracketedExpr :
        NoFailSeq<CharTok<'['>, Store<Expr>, CharTok<']'> > { };

    struct SimpleExpr :
        Or<
			Store<Literal>,
            Store<ParanthesizedExpr>,
            Store<BracketedExpr>,
			NameTok
        > { };

    // Note that unlike typical grammar designs, I have delayed 
    // prcedence handling to the AST processing mechanism.
	// This makes the grammar much simpler
    struct Expr :
        Plus<Store<SimpleExpr> > { };

	struct Eos : 
        CharTok<';'> { };

	struct Initializer :
        Seq<CharTok<'='>, Store<Expr> > { };

    struct CodeBlock :
        NoFailSeq<CharTok<'{'>, StatementList, Finao<CharTok<'}'> > > { };

	struct VarInit :
		Seq<NameTok, Opt<Initializer> > { };

    struct VarDecl :
        StoreCommaList<VAR, VarInit, Eos> { };

    struct ElseStatement :
        NoFailSeq<ELSE, Store<Statement> > { };

    struct IfStatement :
        NoFailSeq<IF, Paranthesized<Store<Expr> >, Store<Statement>, Opt<ElseStatement> > { };

    struct ForEachStatement :
        NoFailSeq<FOREACH, CharTok<'('>, NameTok, CharTok<','>, 
			Store<Expr>, CharTok<')'>, Store<Statement> > { };

    struct ForStatement :
        NoFailSeq<FOR, 
			Seq<CharTok<'('>, VarDecl, Store<Expr>, Eos, Store<Expr>, CharTok<')'> >,
			Store<Statement> > { };

    struct ExprStatement :
        Seq<Store<Expr>, Eos> { };

    struct ReturnStatement :
        NoFailSeq<RETURN, Store<Expr>, Eos> { };    

    struct BreakStatement :
        NoFailSeq<BREAK, Eos> { };    

    struct CaseStatement :
        NoFailSeq<CASE, Paranthesized<Store<Expr> >, Store<CodeBlock> > { };

    struct DefaultStatement :
        NoFailSeq<DEFAULT, Store<CodeBlock> > { };

    struct SwitchStatement :
        NoFailSeq<SWITCH, Paranthesized<Store<Expr> >, CharTok<'{'>, Star<Store<CaseStatement> >, 
            Opt<Store<DefaultStatement> >, CharTok<'}'> > { };

    struct WhileStatement :
        NoFailSeq<WHILE, Paranthesized<Store<Expr> >, Store<CodeBlock> > { };
    
    struct DoStatement :
        NoFailSeq<DO, Store<CodeBlock>, WHILE, Paranthesized<Store<Expr> > > { };

	struct TryCatchStatement :
		NoFailSeq<TRY, Store<CodeBlock>, CATCH, 
			CharTok<'('>, VAR, NameTok, CharTok<')'>, Store<CodeBlock> > { };
    
    struct EmptyStatement :
        Eos { };

	struct ThrowStatement :
		NoFailSeq<THROW, Store<Expr>, Eos> { };

    struct Statement :
        Or<
            Or<
                Store<CodeBlock>,
                Store<VarDecl>,
                Store<IfStatement>,
                Store<SwitchStatement>,
                Store<ForEachStatement>,
                Store<ForStatement>,
                Store<WhileStatement>
            >,
            Or<
				Store<DoStatement>,
                Store<BreakStatement>,
                Store<ReturnStatement>,
				Store<TryCatchStatement>,
				Store<ThrowStatement>,
                Store<EmptyStatement>,
                Store<ExprStatement>
            >
       > { };

    struct StatementList :
        Star<Store<Statement> > { };

    struct Function :
        NoFailSeq<VAR, NameTok, WS, Store<ArgList>, Store<CodeBlock> > { };    
    
    struct Functions : 
        Star<Store<Function> > { };    
	
	struct IncludeTarget : 
		Star<AnyExcept<Or<CharTok<'>'>, NewLine> > > { };

	struct INCLUDE : Keyword<CharSeq<'#','i','n','c','l','u','d','e'> > { };
	
	struct Include :
		NoFailSeq<INCLUDE, CharTok<'<'>, Store<IncludeTarget>, CharTok<'>'> > { };

    struct Script :
        Seq<WS, Star<Or<Store<Function>, Store<Include> > >, Finao<EndOfInput> > { };    
}

#endif
